package com.googlecode.dgwt.client.dojo.reflect;

import java.util.Arrays;
import java.util.List;

import com.googlecode.dgwt.client.dojo.core.JsArray;
import com.googlecode.dgwt.client.dojo.core.JsFunction;
import com.googlecode.dgwt.client.dojo.core.JsMap;
import com.googlecode.dgwt.client.dojo.core.JsObject;
import com.googlecode.dgwt.client.dojo.core.NativeWrapper;
import com.googlecode.dgwt.client.dojo.util.JsUtil;

/**
 * @author wellsantos@wellsantos.com
 * @since 0.01
 */
public class BeanMethod<Bean> implements NativeWrapper {

    private String name;
    private JsFunction function;
    private Class<?> returnType;
    private List<BeanParam> params;
    
    protected BeanMethod() {
    }
    
    public BeanMethod(String name, Class<?> returnType, BeanParam[] params, JsFunction function) {
        assert (name != null && params != null && function != null);
        init(name, returnType, params, function);
    }
    
    protected void init(String name, Class<?> returnType, BeanParam[] params, JsFunction function) {
        this.params = Arrays.asList(params);
        this.returnType = returnType;
        this.function = function;
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public Class<?> getReturnType() {
        return returnType;
    }

    public List<BeanParam> getParams() {
        return params;
    }
    
    public String getJniSignature() {
        String jniSignature = "";
        
        for (BeanParam info : params) {
            jniSignature += info.getJniSignature();
        }
        
        return jniSignature;
    }    
     
    public <T> T call(Bean self, Object ...args) {
        return function.apply(self, args);
    }

    public <T extends JsObject> T callNative(Bean self, Object ...args) {
        return function.applyNative(self, args);
    }

    @Override
    public JsObject toJavaScript() {
        JsMap<Object> map = function.cast();
        
        if (JsUtil.isUndefined(map.get("jniSignature"))) {
            JsArray<JsObject> paramArray = JsArray.create(params.size());
            
            for (BeanParam param : params) {
                paramArray.push(param.toJavaScript());
            }
            
            map.set("jniSignature", getJniSignature());
            map.set("returnType", returnType);
            map.set("params", paramArray);
            map.set("name", name);
        }
        
        return function;
    }

}
